/**
 * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef GE_OP_IMPL_REGISTRY_H
#define GE_OP_IMPL_REGISTRY_H
#include <initializer_list>
#include <string>
#include <map>
#include "graph/debug/ge_error_codes.h"
#include "register/op_impl_kernel_registry.h"

namespace ge {
enum TilingPlacement {
    TILING_ON_HOST = 0,
    TILING_ON_AICPU = 1,
};

class OpImplRegisterV2Impl;
class GRAPH_API_EXPORT OpImplRegisterV2 {
public:
    explicit OpImplRegisterV2(const ge::char_t *op_type);
    OpImplRegisterV2(OpImplRegisterV2 &&register_data) noexcept;
    OpImplRegisterV2(const OpImplRegisterV2 &register_data);
    OpImplRegisterV2 &operator=(const OpImplRegisterV2 &) = delete;
    OpImplRegisterV2 &operator=(OpImplRegisterV2 &&) = delete;
    ~OpImplRegisterV2();

public:
    OpImplRegisterV2 &Tiling(
        ge::OpImplKernelRegistry::TilingKernelFunc tiling_func, size_t max_tiling_data_size = 2048);
    OpImplRegisterV2 &PrivateAttr(const ge::char_t *private_attr);
    OpImplRegisterV2 &PrivateAttr(const ge::char_t *private_attr, int64_t private_attr_val);
    OpImplRegisterV2 &PrivateAttr(const ge::char_t *private_attr, const std::vector<int64_t> &private_attr_val);
    OpImplRegisterV2 &PrivateAttr(const ge::char_t *private_attr, const ge::char_t *private_attr_val);
    OpImplRegisterV2 &PrivateAttr(const ge::char_t *private_attr, float private_attr_val);
    OpImplRegisterV2 &PrivateAttr(const ge::char_t *private_attr, bool private_attr_val);
    OpImplRegisterV2 &PrivateAttr(const ge::char_t *private_attr, const std::vector<float> &private_attr_val);
    template <typename T>
    OpImplRegisterV2 &TilingParse(ge::OpImplKernelRegistry::KernelFunc const tiling_parse_func)
    {
        return TilingParse(tiling_parse_func, CreateCompileInfo<T>, DeleteCompileInfo<T>);
    }
    template <typename T>
    OpImplRegisterV2 &TilingParse(ge::OpImplKernelRegistry::TilingParseFunc const tiling_parse_func)
    {
        return TilingParse(reinterpret_cast<ge::OpImplKernelRegistry::KernelFunc>(tiling_parse_func),
            CreateCompileInfo<T>,
            DeleteCompileInfo<T>);
    }

private:
    OpImplRegisterV2 &TilingParse(ge::OpImplKernelRegistry::KernelFunc tiling_parse_func,
        ge::OpImplKernelRegistry::CompileInfoCreatorFunc creator_func,
        ge::OpImplKernelRegistry::CompileInfoDeleterFunc deleter_func);
    OpImplRegisterV2 &PrivateAttr(const ge::char_t *private_attr, ge::AnyValue private_attr_av);

    template <typename T, typename std::enable_if<(!std::is_array<T>::value), int32_t>::type = 0>
    static void *CreateCompileInfo()
    {
        return new T();
    }
    template <typename T>
    static void DeleteCompileInfo(void *const obj)
    {
        delete reinterpret_cast<T *>(obj);
    }

private:
    std::unique_ptr<OpImplRegisterV2Impl> impl_;
};
}  // namespace ge

#define IMPL_OP_COUNTER(op_type, name, counter) \
    static ge::OpImplRegisterV2 name##counter = ge::OpImplRegisterV2(#op_type)
#define IMPL_OP_COUNTER_NUMBER(op_type, name, counter) IMPL_OP_COUNTER(op_type, name, counter)
#define IMPL_OP(op_type) IMPL_OP_COUNTER_NUMBER(op_type, op_impl_register_##op_type, __COUNTER__)
#define IMPL_OP_DEFAULT() IMPL_OP(DefaultImpl)

#endif  // GE_OP_IMPL_REGISTRY_H